package com.zzl.java8.lambda6;

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

/**
 * 参考链接：
 *  1、https://www.jianshu.com/p/2b24b2ee7902
 *  2、https://www.cnblogs.com/blouson/p/methodReference.html
 *  3、https://blog.csdn.net/weixin_30785593/article/details/97543450
 * description: 学习并了解Java8-Lambda表达式
 * @author 朱正磊
 * @date 2020-04-21 10:34:39
 */
public class LearnLambda {

    /**
     *  采用传统Runnable表达式实现多线程
     */
    @Test
    void test1() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("run...");
            }
        };
        Thread thread = new Thread(runnable);
        // run...
        thread.start();
    }

    /**
     * 采用函数式编程实现Runnable表达式进而实现多线程
     */
    @Test
    void test2() {
        Thread thread = new Thread(() -> System.out.println("run..."));
        // run...
        thread.start();
    }

    /**
     * 无参，无返回值，Lambda体只需一条语句
     */
    @Test
    void test3() {
        Runnable runnable1 = (() -> {System.out.println("run...");});
        // 简化一：可以不用加lambda表达式最外层的那个小括号
        Runnable runnable2 = () -> {System.out.println("run...");};
        // 简化二：当表达式内只有一条语句时，return和大括号可以省略
        Runnable runnable3 = () -> System.out.println("run...");
    }

    /**
     * Lambda需要一个参数，无返回值
     */
    @Test
    void test4() {
        Consumer<String> consumer1 = ((e) -> {System.out.println(e);});
        // 简化一：可以不用加lambda表达式最外层的那个小括号
        Consumer<String> consumer2 = (e) -> {System.out.println(e);};
        // 简化二：当表达式内只有一条语句时，return和大括号可以省略
        Consumer<String> consumer3 = (e) -> System.out.println(e);
        // 简化三：当入参只有一个的时候，入参外面的那个小括号可以省略
        Consumer<String> consumer4 = e -> System.out.println(e);
        // 简化四：可以使用::代替->的写法
        Consumer<String> consumer5 = System.out::println;
    }

    /**
     * Lambda 需要两个参数，并且有返回值
     */
    @Test
    void test5() {
        Comparator<Integer> comparator1 = ((num1, num2) -> {return num1 - num2;});
        // 简化一：可以不用加lambda表达式最外层的那个小括号
        Comparator<Integer> comparator2 = (num1, num2) -> {return num1 - num2;};
        // 简化二：当表达式内只有一条语句时，return和大括号可以省略
        Comparator<Integer> comparator3 = (num1, num2) -> num1 - num2;
        // 简化三：可以使用函数式接口提供的静态方法代替->的写法
        Comparator<Integer> comparator4 = Comparator.comparingInt(num -> num);
    }

    /**
     * 数据类型可以省略，因为可由编译器推断得出，称为“类型推断”
     */
    @Test
    void test6() {
        BinaryOperator<Long> binaryOperator1 = ((Long num1, Long num2) -> num1 + num2);
        // 简化一：可以不用加lambda表达式最外层的那个小括号
        BinaryOperator<Long> binaryOperator2 = (Long num1, Long num2) -> num1 + num2;
        // 简化二：(Long num1, Long num2) 中参数类型可以省略，编译器可以自动推断，如下↓
        BinaryOperator<Long> binaryOperator3 = (num1, num2) -> num1 + num2;
    }

    /**
     * 熟悉方法引用对应的函数式接口
     */
    @Test
    void test7() {
        // 实例对象引用实例方法
        Supplier<String> supplier_11 = () -> "ZhuDi".toUpperCase();
        Supplier<String> supplier_12 = "ZhuDi"::toUpperCase;

        // 类引用(无参)构造函数
        Supplier<String> supplier_21 = () -> new String();
        Supplier<String> supplier_22 = String::new;

        // 类引用实例方法，入参为传入实例对象，入参、出参同类型
        Function<String, String> function_11 = e -> e.toUpperCase();
        Function<String, String> function_12 = String::toUpperCase;

        // Predicate<T>可理解为特殊的Function<T, Boolean>

        Person person = new Person();

        // 须为无参静态方法（静态方法、无参有返回值、类调用）
        Supplier<Boolean> supplier_31 = () -> Person.isTest();
        Supplier<Boolean> supplier_32 = Person::isTest;

        // 实例对象调用实例方法（非静态方法、无参有返回值、实例调用）
        Supplier<String> supplier_41 = () -> person.getName();
        Supplier<String> supplier_42 = person::getName;

        // 无参构造函数
        Supplier<Person> supplier_51 = () -> new Person();
        Supplier<Person> supplier_52 = Person::new;

        // 有参构造函数
        Function<String, Person> function_21 = name -> new Person(name);
        Function<String, Person> function_22 = Person::new;

        BiFunction<String, String, Person> biFunction_11 = (name, gender) -> new Person(name, gender);
        BiFunction<String, String, Person> biFunction_12 = Person::new;

        // 类名调用set方法，特定场景下，可取代反射（非静态方法、有2个参数无返回值第1个为实例对象第2个为方法入参、类调用）
        BiConsumer<Person, String> biConsumer_11 = Person::setName;

        // 类名调用实例方法，入参为传入实例对象（非静态方法、有1个参数为实例对象有返回值、类调用）
        Function<Person, Person> function_31 = p -> {return p.toOpposite();};
        Function<Person, Person> function_32 = Person::toOpposite;

        Consumer<String> consumer_11 = e -> System.out.println(e);
        Consumer<String> consumer_12 = System.out::println;

        // 实战演练
        List<String> list = Arrays.asList("1", "2", "3");
        boolean match = list.stream().anyMatch("1"::equals);
        // LinkedList<String> linkedList = new LinkedList<>(list);
        LinkedList<String> linkedList = list.stream().collect(Collectors.toCollection(LinkedList::new));

        List<Person> personList = Arrays.asList(new Person(20, "zhangsan", "Male"),
                new Person(22, "lisi", "Female"), new Person(24, "wangwu", "Male"));

        ArrayList<Person> personArrayList1 = personList.stream().filter(Person::isMale)
                .collect(Collectors.toCollection(ArrayList::new));

        ArrayList<Person> personArrayList2 = personList.stream().filter(Person::isMale2)
                .collect(Collectors.toCollection(ArrayList::new));

        Person p = new Person(23, "zhaoliu", "Female");
        ArrayList<Person> personArrayList3 = personList.stream().filter(Person::isMale2).filter(p::isUnder)
                .collect(Collectors.toCollection(ArrayList::new));
    }

    /**
     * java8 四大核心函数式接口Function、Consumer、Supplier、Predicate
     */
    @Test
    void test8() {
        // Function<T, R>
        // T：入参类型，R：出参类型
        // 调用方法：R apply(T t);
        // 定义函数示例：
        Function<Integer, Integer> function = e -> e * 10;
        // 调用函数示例：
        Integer result = function.apply(10);
        // 打印输出100
        System.out.println(result);

        // Consumer<T>
        // T：入参类型；没有出参
        // 调用方法：void accept(T t);
        // 定义函数示例：
        Consumer<String> consumer = System.out::println;
        // 调用函数示例：
        // 打印输出hehe
        consumer.accept("hehe");

        // Supplier<R>
        // R：出参类型；没有入参
        // 调用方法：T get();
        // 常用于业务“有条件运行”时，符合条件再调用获取结果的应用场景；运行结果须提前定义，但不运行。
        // 定义函数示例：
        Supplier<Integer> supplier = () -> 100;
        // 调用函数示例：
        Integer r = supplier.get();
        // 打印输出100
        System.out.println(r);

        // Predicate<T>
        // T：入参类型；出参类型是Boolean
        // 调用方法：boolean test(T t);
        // 定义函数示例：
        // 判断是不是偶数
        Predicate<Integer> predicate = e -> e % 2 == 0;
        // 调用函数示例：
        Boolean test = predicate.test(100);
        // 打印输出true
        System.out.println(test);
    }

}
